﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting.Messaging;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace Async.Compute.Bound
{
    class Program
    {
        static void Main(string[] args)
        {
            Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
            Trace.AutoFlush = true;
            TaskFactoryDemo();
            //ParallelDemo();
            //new TimeDemo().Go();
            // string ddlTxt = "Ukrayina Liha@Ultimate Team@Bardays PL@A.Bundesliga@A-League@Airtricity League@ALJ League@Alka Superliga@Allsvenskan@Bundesliga@Bundesliga 2@Cam.Scotiabank@Ekstraklasa@Eredivisie@FL Championship@Football League 1@Football League 2@Hellas Liga@International@K LEAGUE@Legends@Liga Adelante@IGA Bancomer MX@Liga BBVA@Liga Postobon@Ligue 1@Ligue 2@MLS@Primeira Liga@Primera Division@Pro League@Raiffeisen SL@Russian League@Scotland League@Scottish Prem@Serie A@Serie B@South African FL@Super Lig@Tippeligaen";
            //List<string> tmp = ddlTxt.Split('@').ToList<string>();
            //IEnumerable<string> sort = tmp.OrderBy(n => n.ToUpper());
            Console.ReadLine();
        }

        static void ThreadPoolDemo()
        {
            Trace.WriteLine("Main thread:queuing an asynchronous operation");
            ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5);
            Trace.WriteLine("Main thread:Doing other work here...");
            Thread.Sleep(10000);//模拟其它工作10秒
            Trace.WriteLine("Hit <Enter> to end this program...");


        }

        static void ComputeBoundOp(object state)
        {
            //这个方法由一个线程池线程执行
            Trace.WriteLine(string.Format("In ComputeBoundOp state:={0}", state));
            Thread.Sleep(1000);//模拟工作1秒
            //这个方法返回后,线程回到池中,等待另一个任务
        }

        static void ExecutionContextDemo()
        {
            //将一些数据放到Main线程的逻辑调用上下文中
            CallContext.LogicalSetData("Name", "Jeffry");

            //初始化一个线程池的线程做一些工作,
            //线程池线程能访问逻辑调用上下文数据
            ThreadPool.QueueUserWorkItem(state => Trace.WriteLine("Name = " + CallContext.LogicalGetData("Name")));
            ThreadPool.QueueUserWorkItem(state => Trace.WriteLine("Name = " + CallContext.LogicalGetData("Name")));

            //现在,阻止Main线程的执行上下文的流动
            ExecutionContext.SuppressFlow();

            //初始化一个线程池的线程做一些工作,
            //线程池线程不能访问逻辑调用上下文数据
            ThreadPool.QueueUserWorkItem(state => Trace.WriteLine("Name = " + CallContext.LogicalGetData("Name")));

            //恢复Main线程的执行上下文流动
            ExecutionContext.RestoreFlow();
            ThreadPool.QueueUserWorkItem(state => Trace.WriteLine("Name = " + CallContext.LogicalGetData("Name")));

        }

        static void CancellationDemo()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            //将CancellationToken和要数到的数传入操作
            ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 600));
            Trace.WriteLine("Press <Enter> to cancel the operation.");
            Console.ReadLine();
            cts.Cancel();
            //如果Count方法已经返回,Cancel没有任何效果
            //Cancel立即返回,方法从这里继续运行...
        }

        static void Count(CancellationToken token, int countTo)
        {
            Trace.WriteLine("Call me thread name is " + Thread.CurrentThread.Name);
            for (int count = 0; count < countTo; count++)
            {
                if (token.IsCancellationRequested)
                {
                    Trace.WriteLine("Count is cancelled");
                    break;
                }
                Trace.WriteLine(count);
                Thread.Sleep(1000);//出于演示目的而浪费一些时间
            }

            Trace.WriteLine("Count is done");

        }

        static void CancellationLinkDemo()
        {
            var cts1 = new CancellationTokenSource();
            cts1.Token.Register(() => Trace.WriteLine("cts1 canceled"));

            var cts2 = new CancellationTokenSource();
            cts2.Token.Register(() => Trace.WriteLine("cts2 canceled"));

            //创建一个新的CancellationTokenSource,它在cts1或cts2取消时被取消
            var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);
            linkedCts.Token.Register(() => Trace.WriteLine("linkedCts canceled"));

            cts2.Cancel();

            Trace.WriteLine(string.Format("cts1 canceled = {0},cts2 canceled = {1},linkedCts = {2}", cts1.IsCancellationRequested, cts2.IsCancellationRequested, linkedCts.IsCancellationRequested));


        }

        static void UsingTaskInsteadOfQueueUserWorkItemDemo()
        {
            ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5);
            Task task = new Task(ComputeBoundOp, 5);
            task.Start();
        }

        static void WaitForResultDemo()
        {
            //创建一个Task(现在还没有开始运行)
            Task<int> t = new Task<int>(n => Sum((int)n), 100000);

            //可以以后再启动
            t.Start();

            try
            {
                //可以选择显示地等待任务完成
                t.Wait();//还有一些重载版本能接受timeout/CancellationToken值

                Trace.WriteLine("The Sum is :" + t.Result);
            }
            catch (AggregateException e)
            {

            }
        }

        static void WaitAnyOrAllDemo()
        {
            Task<int> t_10 = new Task<int>(n => Sum((int)n), 10);
            Task<int> t_20 = new Task<int>(n => Sum((int)n), 20);
            Task<int> t_30 = new Task<int>(n => Sum((int)n), 30);
            CancellationTokenSource cts = new CancellationTokenSource();
            t_30.Start();
            t_20.Start();
            t_10.Start();
            Trace.WriteLine("Press <Enter> to cancel the operation.");
            Console.ReadLine();
            cts.Cancel();
            Task.WaitAny(new Task[] { t_10, t_20, t_30 }, cts.Token);

        }

        static int Sum(int n)
        {
            int sum = 0;
            for (; n > 0; n--)
            {
                checked { sum += n; }
                //Trace.WriteLine("The current sum is :" + sum);
                //Thread.Sleep(1000);
            }
            return sum;
        }

        static void CancelTaskDemo()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            Task<int> task = new Task<int>(() => Sum(cts.Token, 10), cts.Token);
            task.Start();
            Thread.Sleep(10000);
            //在之后的某个时间,取消CancellationTokenSource以取消Task
            cts.Cancel();//这是一个异步请求,Task可能已经完成了
            try
            {
                //如果任务已经取消了,Result会抛出一个AggregateException
                Trace.WriteLine("The sum is " + task.Result);
            }
            catch (AggregateException e)
            {
                //将任何OperationCanceledException对象都视为已处理
                //其它任何异常都造成抛出一个新的AggregateException,其中只包含未处理的异常
                e.Handle(x => x is OperationCanceledException);

                //所有异常处理好之后才会执行下面这行
                Trace.WriteLine("Sum was canceled");
            }
        }

        static int Sum(CancellationToken ct, int n)
        {
            int sum = 0;
            for (; n > 0; n--)
            {
                checked { sum += n; }
                //Trace.WriteLine("The current sum is :" + sum);
                //Thread.Sleep(200);
                ct.ThrowIfCancellationRequested();
            }
            return sum;
        }

        static void ContinueTaskDemo()
        {
            //创建Task,推迟启动它,继续另一个任务
            Task<int> task = new Task<int>(n => Sum((int)n), 10);

            //ContinueWith返回一个Task,但一般都不再关系这个对象
            Task cwt = task.ContinueWith(t => Trace.WriteLine("The sum is : " + task.Result));


            //可以在以后某个时间启动任务
            task.Start();
        }

        static void ContinueTask2Demo()
        {
            //创建Task,推迟启动它,继续另一个任务
            Task<int> task = new Task<int>(n => Sum((int)n), 1000000);

            task.ContinueWith(t => Trace.WriteLine("the sum is :" + task.Result), TaskContinuationOptions.OnlyOnRanToCompletion);

            task.ContinueWith(t => Trace.WriteLine("the sum throw :" + task.Exception), TaskContinuationOptions.OnlyOnFaulted);

            task.ContinueWith(t => Trace.WriteLine("the sum was canceled "), TaskContinuationOptions.OnlyOnCanceled);

            task.Start();
        }

        static void SubTaskDemo()
        {
            //创建一个数组来存储结果
            var results = new List<int>(3);
            //这个任务创建并启动3个子任务
            Task<List<int>> parent = new Task<List<int>>(
                () =>
                {
                    new Task(() => results.Add(Sum(10000)), TaskCreationOptions.AttachedToParent).Start();
                    new Task(() => results.Add(Sum(20000)), TaskCreationOptions.AttachedToParent).Start();
                    new Task(() => results.Add(Sum(30000)), TaskCreationOptions.AttachedToParent).Start();
                    return results;
                }
                );

            //父任务及其子任务运行完成后,用一个延续任务显示结果
            var cwt = parent.ContinueWith(task => Array.ForEach(parent.Result.ToArray(), Console.WriteLine));
            //启动父任务,以便它启动子任务
            parent.Start();


        }

        static void TaskFactoryDemo()
        {
            Task parent = new Task(() =>
            {
                var cts = new CancellationTokenSource();
                TaskFactory<int> tf = new TaskFactory<int>(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                //这个任务创建并启动3个子任务
                var childTasks = new List<Task<int>>{
    tf.StartNew(() => Sum( cts.Token,10000)),
    tf.StartNew(() => Sum( cts.Token,20000)),
    tf.StartNew(() => Sum( cts.Token,Int32.MaxValue - 10)),
    };

                //任何子任务抛出异常,就取消其余子任务
                foreach (Task<int> cTask in childTasks)
                {
                    cTask.ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);
                }

                //所有子任务完成后,从未出错/未取消的任务获取返回的最大值,
                //然后将最大值传给另一个任务来显示最大值
                tf.ContinueWhenAll(childTasks.ToArray(), completed_tasks => completed_tasks.Where(t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result), CancellationToken.None)
                    .ContinueWith(t => Trace.WriteLine("the maximum is : " + t.Result), TaskContinuationOptions.ExecuteSynchronously);

            });

            //子任务完成后,也显示任何未处理的异常
            parent.ContinueWith(p =>
            {
                //将所有文本放到一个StringBuilder中,并只调用Trace.WriteLine一次,
                //因为这个任务可能和上面的任务并行执行,而我不希望任务的输出变得不连续
                StringBuilder sb = new StringBuilder("the following exception(s) occurred : " + Environment.NewLine);
                foreach (var e in p.Exception.Flatten().InnerExceptions)
                {
                    sb.AppendLine(" " + e.GetType().ToString());
                }

                Trace.WriteLine(sb.ToString());
            }, TaskContinuationOptions.OnlyOnFaulted);

            //启动父任务,便于它启动它的子任务
            parent.Start();
        }

        static void TaskSchedulerDemo()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MyForm());
        }


        static void ParallelDemo()
        {
            DirectoryBytes(@"E:\Book\Asp.net", "*.*", SearchOption.AllDirectories);
        }

        static Int64 DirectoryBytes(string path, string search_pattern, SearchOption search_option)
        {
            var files = Directory.EnumerateFiles(path, search_pattern, search_option);
            Int64 master_total = 0;
            int init_count = 0;
            int body_count = 0;
            int finally_count = 0;
            ParallelLoopResult result = Parallel.ForEach<string, Int64>(files, () =>
                {
                    Interlocked.Increment(ref init_count);
                    //localInit:每个任务开始之前调用一次
                    //每个任务开始之前,总计数值都初始化为0
                    return 0;//将task_local_total初始值设为0
                },
                (file, loop_state, index, task_local_total) =>
                {
                    //body:每个工作项调用一次
                    //获得这个文件的大小,把它添加到这个任务的累加值上
                    Int64 file_length = 0;
                    FileStream fs = null;
                    try
                    {
                        fs = File.OpenRead(file);
                        file_length = fs.Length;
                    }
                    catch (IOException)
                    {
                    }
                    finally
                    {
                        if (fs != null) { fs.Dispose(); }
                    }
                    var total = task_local_total + file_length;
                    Interlocked.Increment(ref body_count);
                    //Interlocked.Add(ref master_total, file_length);
                    return total;
                },
                    task_local_total =>
                    {  //localFinally:每个任务完成时调用一次
                        //将这个任务的总计值(task_local_total)加到总的总计值(master_total)上
                        Interlocked.Increment(ref finally_count);
                        Interlocked.Add(ref master_total, task_local_total);
                    }
                        );

            return master_total;

        }

    }

}




